﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using Cubicle.Core.Config;

namespace Cubicle.Core.Processors.Parameter
{

    [Export]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class ParameterProcessor : QueueWrapper<ParameterRequest>
    {
        private const string QueueName = "Parameter";

        [ImportingConstructor]
        public ParameterProcessor(CompositionContainer container, EngineConfig config) 
            : base(container, config, QueueName) { }

        public T[] Process<T>(IEnumerable<ParameterRequest> requests)
        {
            var reqArray = requests as ParameterRequest[] ?? requests.ToArray();
            var results = new T[reqArray.Length];
            for (int i = 0; i < reqArray.Length; i++)
            {
                var request = reqArray[i];
                var result = Process(request);
                if (result.ReqType != RequestType.Completed)
                    //throw new Exception("Failed to resolve parameter");
                    return null;
                results[i] = (T)result.Result;
            }

            return results;
        }
    }

    public static class ParameterProcessorExtensions
    {
        
        public static T[] Process<T>(this IEnumerable<ParameterRequest> requests, ParameterProcessor processor)
        {
            return processor.Process<T>(requests);
        }

        public static T[] Process<T>(this object[] sources, Type[] targetTypes, ParameterProcessor processor)
        {
            return sources
                .Zip(targetTypes, (source, type) => new ParameterRequest(type, source))
                .Process<T>(processor);
        }

        public static T[] Process<T>(this object[] sources, Type targetType, ParameterProcessor processor)
        {
            return sources.Process<T>(sources.Select(x => targetType).ToArray(), processor);
        }

        public static T[] Process<T>(this Type[] targetTypes, object[] sources, ParameterProcessor processor)
        {
            return sources.Process<T>(targetTypes, processor);
        }

    }

}
